package com.centriole.service.workflow.service;

import com.centriole.service.workflow.dao.ProcessMapper;
import com.centriole.service.workflow.util.CommonUtil;
import com.centriole.service.workflow.util.UserUtils;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.HistoricProcessInstanceEntity;
import org.activiti.engine.impl.persistence.entity.HistoricVariableInstanceEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipInputStream;

/**基于工作流7大接口 封装后的接口
 * @author wukai
 *
 */
@Service
public class ActManagerService {
	public static final String CLASSPATH = "1";
	public static final String STRING = "2";
	public static final String ZIP = "3";
	@Resource
	private ProcessEngine processEngine;
	/**
	 * 流程仓库Service,用于部署、删除、查询流程资源等
	 */
	@Resource
	private RepositoryService repositoryService;
	/**
	 * 运行时Service,用于处理正在运行状态的流程实例
	 */
	@Resource
	private RuntimeService runtimeService;
	/**
	 * 任务Service,用于管理、查询任务,例如：办理、签收、指派等
	 */
	@Resource
	private TaskService taskService;
	/**
	 * 历史Service,用于查询历史数据,例如：流程实例、任务、变量等
	 */
	@Resource
	private HistoryService historyService;
	/**
	 * 身份Service,用于管理、查询用户
	 */
	@Resource
	private IdentityService identityService;
	@Resource
	private ManagementService managementService;
	@Resource
	private FormService formService;

	/*
		注入这个Mapper破环了 ActManagerService的封装性，注入这个主要是让指定用户id强制签收一个Task
	 */
	@Resource
	ProcessMapper processMapper;
	
	/**部署流程
	 * @param processKey 流程定义Key
	 * @param resource
	 * @param type 部署类型，1 资源路径，2 字符串，3 zip包
	 */
	public void deploy(String processKey, String resource ,String type){
		try {
			Deployment deployment;
			DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
			if(CLASSPATH.equals(type)){
				deployment = deploymentBuilder.addClasspathResource(resource).deploy();
			}else if(STRING.equals(type)){
				deployment = deploymentBuilder.addString(processKey+".bpmn",resource).deploy();
			}else if(ZIP.equals(type)){
				InputStream in = this.getClass().getClassLoader().getResourceAsStream(resource);
				ZipInputStream zipInputStream = new ZipInputStream(in);
				deployment = deploymentBuilder.addZipInputStream(zipInputStream).deploy();
			}else{
				throw new Exception("请选择正确类型");
			}
			System.out.println("部署ID："+deployment.getId()); 
			System.out.println("部署时间："+deployment.getDeploymentTime());
		} catch (Exception e) {
			// TODO 异常统一处理
			e.printStackTrace();
			throw new RuntimeException("processKey 不符合 NCName 标准");

		}
	}
	
	/**启动流程
	 * @param definitionKey 流程定义key
	 * @param businessKey 流程业务key
	 * @param variables 流程参数
	 * @param userId 流程发起人
	 */
	public String start(String definitionKey, String businessKey, Map<String, Object> variables, String userId){
		try {
			if(CommonUtil.isNotEmpty(userId)){
				identityService.setAuthenticatedUserId(userId);
			}
			ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(definitionKey, businessKey, variables);
			System.out.println("启动流程实例ID："+processInstance.getId());
			return processInstance.getId();
		} catch (Exception e) {
			// TODO 异常统一处理
			e.printStackTrace();
		} finally {
			identityService.setAuthenticatedUserId(null);
		}
		return null;
	}


	/**
	 * 指定一个流程实例 查询对应历史信息
	 * @param instanceId 流程实例id
	 * @return
	 */
	public HistoricProcessInstance findHistoricInstaces(String instanceId){
		List<HistoricProcessInstance> proInstances = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).list();
		initVariable(proInstances);
		return proInstances.get(0);
	}

	/**查询用户发起的流程
	 * @param userId 用户ID
	 * @param state 状态 all全部、run运行中、history已结束
	 * @param definitionKey 流程定义Key
	 * @return
	 */
	public List<HistoricProcessInstance> findApplyInstaces(String userId, String state, String definitionKey){
		HistoricProcessInstanceQuery historyQuery = historyService.createHistoricProcessInstanceQuery();
		if( CommonUtil.isNotEmpty(userId) ){
			historyQuery.startedBy(userId);
		}
		if(CommonUtil.isNotEmpty(definitionKey)){
			historyQuery.processDefinitionKey(definitionKey);
		}
		if (CommonUtil.isNotEmpty(state)&&"0".equals(state)) {
			historyQuery.unfinished();
		} else if (CommonUtil.isNotEmpty(state)&&"1".equals(state)) {
			historyQuery.finished();
		}
		List<HistoricProcessInstance> proInstances= historyQuery.orderByProcessInstanceEndTime().desc().list();
		initVariable(proInstances);
		return proInstances;
	}

	/**添加流程参数到结果集
	 * @param proInstances
	 */
	private void initVariable(List<HistoricProcessInstance> proInstances) {
		for (HistoricProcessInstance h : proInstances) {
			HistoricProcessInstanceEntity hEntity = (HistoricProcessInstanceEntity)h;
			List<HistoricVariableInstance> vars = historyService.createHistoricVariableInstanceQuery().processInstanceId(hEntity.getProcessInstanceId()).list();
			List<HistoricVariableInstanceEntity> varEntitys = new ArrayList<HistoricVariableInstanceEntity>();
			for (HistoricVariableInstance hv : vars) {
				varEntitys.add((HistoricVariableInstanceEntity)hv);
			}
			hEntity.setQueryVariables(varEntitys);
			hEntity.setSuperProcessInstanceId(hEntity.getProcessInstanceId());
		}
	}


	/**
	 *	获取流程变量
	 * @param h
	 * @param variableName
	 * @param <T>
	 * @return
	 */
	public <T>T getVariablesByHistoricInstance(HistoricProcessInstance h , String variableName){
		if(StringUtils.isBlank(variableName)) return null;
		HistoricProcessInstanceEntity hEntity = (HistoricProcessInstanceEntity)h;
		List<HistoricVariableInstance> vars = historyService.createHistoricVariableInstanceQuery().processInstanceId(hEntity.getProcessInstanceId()).list();
		List<HistoricVariableInstanceEntity> varEntitys = new ArrayList<HistoricVariableInstanceEntity>();
		List<HistoricVariableInstanceEntity> singleVar = varEntitys.parallelStream().filter(e -> variableName.equals(e.getVariableName())).collect(Collectors.toList());
		return singleVar.size() > 0? (T)singleVar.get(0):null;
	}
	
	/**查询待办任务
	 * @param processDefinitionKey
	 * @param userId
	 * @param candidateGroups
	 * @return
	 */
	public List<Task> findToDoTasks(String processDefinitionKey, String userId, List<String> candidateGroups){
		TaskQuery query = taskService.createTaskQuery();
		if(CommonUtil.isNotEmpty(processDefinitionKey)){
			if(CommonUtil.isNotEmpty(candidateGroups))
				query.or().taskCandidateGroupIn(candidateGroups).taskCandidateOrAssigned(userId).endOr().processDefinitionKey(processDefinitionKey);
			else
				query.or().taskCandidateOrAssigned(userId).endOr().processDefinitionKey(processDefinitionKey);
		}else{
			if(CommonUtil.isNotEmpty(candidateGroups))
				query.or().taskCandidateGroupIn(candidateGroups).taskCandidateOrAssigned(userId).endOr();
			else
				query.taskCandidateOrAssigned(userId);
		}
		List<Task> activeTaskList = query.active().list();
		List<Task> suspendedTaskList = query.suspended().list();
		for(Task t : activeTaskList){
			t.setFormKey("active");
		}
		for(Task t : suspendedTaskList){
			t.setFormKey("suspended");
		}
		//不再将被挂起的流程查询出来
	//	activeTaskList.addAll(suspendedTaskList);		//suspendedTaskList加入到activeTaskList中去
		return activeTaskList;
	}
	
	/**根据instanceId 获取任务
	 * @param instanceId
	 * @return
	 */
	public List<Task> findTasksByInstanceId(String instanceId){
		TaskQuery query = taskService.createTaskQuery();
		query.processInstanceId(instanceId);
		return query.list();
	}
	
	/**查询办理过得任务
	 * @param userId 用户ID
	 * @param state 状态 all全部、run运行中、finish已结束
	 * @return
	 */
	public List<HistoricProcessInstance> findProcessedInstances(String userId, String state, String processDefinitionKey){
		processDefinitionKey = CommonUtil.isEmpty(processDefinitionKey)?"":" AND arp.KEY_='"+processDefinitionKey+"'";
		if (CommonUtil.isNotEmpty(state)&&"run".equals(state)) {
			state = " AND ahp.END_TIME_ IS NULL";
		} else if (CommonUtil.isNotEmpty(state)&&"finish".equals(state)) {
			state = " AND ahp.END_TIME_ IS NOT NULL";
		} else {
			state = "";
		}
		String sql = "SELECT ahp.* FROM "+managementService.getTableName(HistoricProcessInstance.class)+" ahp "+
				"LEFT JOIN "+managementService.getTableName(ProcessDefinition.class)+" arp ON ahp.PROC_DEF_ID_=arp.ID_ "+
				"LEFT JOIN "+managementService.getTableName(HistoricTaskInstance.class)+" aht ON ahp.PROC_INST_ID_=aht.PROC_INST_ID_ "+
				"WHERE aht.ASSIGNEE_='"+userId+"' AND aht.DELETE_REASON_='completed'"
				+processDefinitionKey+state+" GROUP BY ahp.PROC_INST_ID_ ORDER BY ahp.START_ACT_ID_ DESC";
		System.out.println(sql);
		List<HistoricProcessInstance> instanceList = historyService.createNativeHistoricProcessInstanceQuery().sql(sql).list();;
		initVariable(instanceList);
		return instanceList;
	}
	
	/**办理任务（签收和办理同时执行）
	 * @param taskId 任务ID
	 * @param userId 办理人ID
	 * @param variables 办理参数
	 */
	public void complete(String taskId, String userId, Map<String, Object> variables){
		 userId = StringUtils.isBlank( userId  )?UserUtils.currentUserInfo().getEmpId()+"":userId;
		synchronized (taskId) {
			//签收任务
			taskService.claim(taskId, userId);
			//办理任务
	        taskService.complete(taskId, variables);
	        //在'act_hi_taskinst' 签收userId
			System.err.println("用户["+userId+"]签收了任务["+taskId+"]");
			processMapper.signTask(taskId,userId);
 		}
	}
	
	/**判断是否为最后一个任务
	 * @param task
	 * @return
	 */
	public boolean lastTask(Task task){
		ProcessDefinitionEntity entity = (ProcessDefinitionEntity)repositoryService.getProcessDefinition(task.getProcessDefinitionId());
		List<ActivityImpl> ActivityImpls = entity.getActivities();
		ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
		String activitiId = execution.getActivityId();
		
		for(ActivityImpl activityImpl:ActivityImpls){
			String id = activityImpl.getId();
			if(activitiId.equals(id)){
				System.out.println("当前任务："+activityImpl.getProperty("type")); //输出某个节点的某种属性
				List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();//获取从某个节点出来的所有线路
				for(PvmTransition tr:outTransitions){
//					tr.getProperty("documentation");//条件
					PvmActivity ac = tr.getDestination(); //获取线路的终点节点ac
					System.out.println("下一步任务："+ac.getProperty("type"));
					//添加条件判断
					if("endEvent".equals(ac.getProperty("type"))){
						return true;
					}else if("inclusiveGateway".equals(ac.getProperty("type"))){
						List<PvmTransition> acOutTransitions = ac.getOutgoingTransitions();
						if(CommonUtil.isNotEmpty(acOutTransitions) && "endEvent".equals(acOutTransitions.get(0).getProperty("type"))){
							// TODO 查看是否需要其他判断
							return true;
						}
					}
				}
				break;
			}
		}
		return false;
	}
	
	/**挂起流程
	 * @param instanceId
	 */
	public void suspendInstance(String instanceId){
		runtimeService.suspendProcessInstanceById(instanceId);
	}
	
	
	/**激活流程
	 * @param instanceId
	 */
	public void activateInstance(String instanceId){
		runtimeService.activateProcessInstanceById(instanceId);
	}
	
	/**
	 * 通过taskId获取task对应的流程实例id
	 * @param taskId		任务id
	 * @return	String 流程实例id
	 */
	public String getInstanceIdByTaskId(String taskId) {
		 Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
		 return t.getProcessInstanceId();		//通过任务id获取流程id
	}
	
	/**根据taskID获取task信息
	 * @param taskId
	 * @return	List<> Task集合
	 */
	public List<Task> getTasksByTaskId(String taskId){
		 List<Task> tasks = getTaskByInstanceId( getInstanceIdByTaskId(taskId) );
		 return tasks;
	}
	
	/**根据taskID获取task信息
	 * @param taskId
	 * @return	Task	单个Task对象
	 */
	public Task getSingleTaskByTaskId(String taskId){
		 return taskService.createTaskQuery().taskId(taskId).singleResult();
	}
	
	/**根据instanceID获取task信息
	 * @return
	 */
	public List<Task> getTaskByInstanceId(String instanceId){
		return taskService.createTaskQuery().processInstanceId(instanceId).list();
	}
	
	
	/**根据流程定义key暂停流程定义
	 * @param processDefinitionKey
	 */
	public void suspendProcessDefinition(String processDefinitionKey){
		repositoryService.suspendProcessDefinitionByKey(processDefinitionKey,true,null);
	}
	/**根据流程定义key激活流程定义
	 * @param processDefinitionKey
	 */
	public void activateProcessDefinitionByKey(String processDefinitionKey){
		repositoryService.activateProcessDefinitionByKey(processDefinitionKey, true, null);
	}
	/**根据instanceid结束流程
	 * @param instanceId
	 */
	public void endActiviti(String instanceId) {
		processEngine.getRuntimeService().deleteProcessInstance(instanceId ,"任务被发起人终止");
	}

	/**
	 * 查询历史实例流程
	 * @return
	 */
	public int countFinished(){
		return historyService.createHistoricProcessInstanceQuery().list().size();
	}

}
